package org.semanticflash.rdf.sparql.results
{
	
	import org.semanticflash.rdf.values.*;
	
	
	/**
	 * 
	 * Batch parser for "application/sparql-results+xml" documents.
	 * 
	 * TODO: We are only parsing "select" responses for now ( Ask is missing )
	 * TODO: Typed Literals
	 * 
	 * @author aldo.bucchi@univrz.com
	 * 
	 */	
	public class SPARQLResults
	{
		
		private static var ns:Namespace = new Namespace( "http://www.w3.org/2005/sparql-results#" );		
		
		public function get isAsk( ):Boolean
		{
			return false;
		}
		
		
		public function get isSelect( ):Boolean
		{
			return true;
		}
		
		
		private var _results:Array = [ ];
		/**
		 * An Array containing all the rows.
		 * 
		 * <pre>
		 * results[n][binding:String] = value:RDFValue
		 * </pre>
		 * 
		 * @return 
		 * 
		 */		
		public function get results( ):Array
		{
			return _results;
		}
		
		/**
		 * @private
		 * 			Use static method parse() to create an instance
		 * 
		 * @param results
		 * 
		 */		
		public function SPARQLResults( results:Array )
		{
			_results = results;
		}
		
		/**
		 * @param sparqlXML
		 * @return 
		 * 
		 */		
		public static function parse( sparqlResults:XML ):SPARQLResults
		{

			var bnodeCache:Object = {};
			var results:Array = new Array( );

			for each ( var resultNode:XML in sparqlResults..ns::result )
			{
				var resultObj:Object = {};
				for each ( var bindingNode:XML in resultNode.ns::binding )
				{
					var valueNode:XML, value:RDFValue;

					for each ( valueNode in bindingNode.ns::literal )
						value = RDFPlainLiteral.instance( valueNode.toString( ) );

					for each ( valueNode in bindingNode.ns::uri )
						value = IRI.instance( valueNode.toString( ) );
					
					for each ( valueNode in bindingNode.ns::bnode )
						value = getBNode( valueNode.toString( ), bnodeCache );

					if ( value == null )
					{
						// TODO: yield error, this shouldn't happen
						continue;
					}
					resultObj[ bindingNode.@name.toString( ) ] = value;
				}
				results.push( resultObj );			
			}
			return new SPARQLResults( results );
		}
		
		
		private static function getBNode( localName:String, cache:Object ):IRI
		{
			if ( ! cache[ localName ] )			
			{
				cache[ localName ] = IRI.bNode( );
			}
			return cache[ localName ] as IRI;
		}
		
		/**
		 * 
		 * If all you need to parse is a count result, use this method.
		 * 
		 * @param sparqlResults
		 * @return 
		 * 		Count or -1 if parsing fails
		 * 
		 */		
		public static function parseCount( sparqlResults:XML ):int
		{
			use namespace sparql_results;
            var lit:XML = sparqlResults..literal[0];
            if ( lit != null )
                return int( Number( lit.toString( ) ) );
            return -1;			
		}
		
	}
}